<?php


namespace App\Game\Core;


class PaiXing
{

    // 底金
    private static $point = 1;

    // 额外奖励番数
    private static $reward = [
        'qys' => ['name' => '清一色', 'bonus' => 4], //清一色 x4番
        'jgd' => ['name' => '金钩钓', 'bonus' => 4], //金钩钓 x4番
        'dyj' => ['name' => '带幺九', 'bonus' => 4], //带幺九 x4番
        'jd' => ['name' => '将对', 'bonus' => 8], //将对 x4番
        'long' => ['name' => '龙', 'bonus' => 2], //龙 x2番
    ];

    // 胡牌牌型 ， d：对 g：杠 p：碰 s：顺， key:牌型  ，name:胡型名称，bonus：番数
    // flag：胡型有额外特殊奖励条件 0.无（七对除外） 1.带幺九 2.金钩钓 3.带幺九+金钩钓 4.不计杠
    private static $paixing = [
        'ddddddd' => ['name' => '七对', 'bonus' => 4, 'flag' => 4],
        'dgggg' => ['name' => '十八罗汉', 'bonus' => 64, 'flag' => 4],
        'dgggp' => ['name' => '碰碰胡', 'bonus' => 2, 'flag' => 2],
        'dgggs' => ['name' => '平胡', 'bonus' => 1, 'flag' => 0],
        'dggpp' => ['name' => '碰碰胡', 'bonus' => 2, 'flag' => 2],
        'dggps' => ['name' => '平胡', 'bonus' => 1, 'flag' => 0],
        'dggss' => ['name' => '平胡', 'bonus' => 1, 'flag' => 0],
        'dgppp' => ['name' => '碰碰胡', 'bonus' => 2, 'flag' => 2],
        'dgpps' => ['name' => '平胡', 'bonus' => 1, 'flag' => 0],
        'dgpss' => ['name' => '平胡', 'bonus' => 1, 'flag' => 0],
        'dgsss' => ['name' => '平胡', 'bonus' => 1, 'flag' => 0],
        'dpppp' => ['name' => '碰碰胡', 'bonus' => 2, 'flag' => 3],
        'dppps' => ['name' => '平胡', 'bonus' => 1, 'flag' => 1],
        'dppss' => ['name' => '平胡', 'bonus' => 1, 'flag' => 1],
        'dpsss' => ['name' => '平胡', 'bonus' => 1, 'flag' => 1],
        'dssss' => ['name' => '平胡', 'bonus' => 1, 'flag' => 1],
    ];

    public static $errMsg = '';

    public static function checkPaiXing(array $cards, array $peng = [], array $gang = [])
    {
        $colors = self::bindColor($cards);
//        dd('colors', $colors);
        $types = self::bindType($cards, $gang);
//        dd('types', $types);

        $type = $types['px'];


        if (count($colors) > 2) {
            return '胡牌失败，手牌花色大于2种！';
        }

        if (!isset(self::$paixing[$type])) {
            return '胡牌失败，数据错误，没有该胡型！';
        }

        //---------------------- 结算 start -----------------------------

        // 获取胡型奖励信息
        $reward = self::bindReward($cards, $colors, $type, $peng, $gang);
        // 根数
        $genNum = $types['gen'];
        // 杠数
        $gangNum = !empty($gang) ? count($gang) : 0;

        //龙七对单独处理，根数还需减扣1
        if ($type == 'ddddddd') {
            $arr = [];
            foreach ($cards as $v) {
                foreach ($v as $m) {
                    $arr[] = $m;
                }
            }
            $arr = array_count_values($arr);
            foreach ($arr as $k => $v) {
                if ($v == 4) {
                    $genNum += 1;
                }
            }
            if ($genNum > 0) {
                $reward[] = self::$reward['long'];
                $genNum -= 1;
            }
        }
        //十八罗汉不计杠
        if ($type == 'dgggg') {
            $gangNum = 0;
        }

        // 根奖励 x2 番
        $genBonus = $genNum > 0 ? $genNum * 2 : 1;


        // 杠奖励 x2 番
        $gangBonus = $gangNum > 0 ? $gangNum * 2 : 1;

        // 总番数
        $totalBonus = $genBonus * $gangBonus;
        // 所有胡型番数相乘
        foreach ($reward as $v) {
            $totalBonus *= $v['bonus'];
        }
        // 积分 (底金 x 总番数 )
        $points = self::$point * $totalBonus;

        $totalRewardName = self::bindTotalRewardName($reward);

        //---------------------- 结算 end -----------------------------
        return [
            'reward' => $reward,  // 牌型列表
            'total_gen' => $genNum,     // 根数
            'total_gang' => $gangNum,   // 杠数
            'total_reward_name' => $totalRewardName,
            'total_bonus' => $totalBonus,
            'points' => $points
        ];
    }

    // 绑定胡型总名称，例如：清龙七对
    private static function bindTotalRewardName(array $reward)
    {
        $num = count($reward);
        if ($num == 1) {
            return $reward[0]['name'];
        }

        $firstName = $reward[1]['name'];
        $secondName = $num == 3 ? $reward[2]['name'] : '';
        $thirdName = $reward[0]['name'] != '平胡' ? $reward[0]['name'] : '';

        return $firstName . $secondName . $thirdName;
    }

    // 绑定胡型奖励信息：【胡型名称，番数】
    private static function bindReward(array $cards, array $colors, string $type, array $peng,
                                       array $gang)
    {
        // 基础胡
        $reward[] = ['name' => self::$paixing[$type]['name'], 'bonus' => self::$paixing[$type]['bonus']];

        // 额外奖励胡
        $qys = empty($colors) ? false : (count($colors) > 1 ? false : true);
        // 清一色
        if ($qys) {
            $reward[] = self::$reward['qys'];
        }
        $flag = self::$paixing[$type]['flag'];
        // 带幺九
        if (in_array($flag, [1, 3])) {
            if (self::checkDyj($cards)) {
                array_splice($reward, 0, 1);
                array_unshift($reward, self::$reward['dyj']);
            }
        }
        // 金钩钓 、将对
        if (in_array($flag, [2, 3])) {
            // 金钩钓
            if (self::checkJgd($cards, $peng, $gang)) {
                array_splice($reward, 0, 1);
                array_unshift($reward, self::$reward['jgd']);
            }
            // 将对
            if (self::checkJd($cards)) {
                $reward = [self::$reward['jd']];
            }
        }
        return $reward;
    }

    // 校验带幺九，顺子，刻子和将牌都含一或九
    private static function checkDyj(array $cards)
    {
        $num = 0;
        foreach ($cards as $v) {
            foreach ($v as $m) {
                if (in_array($m, [1, 9, 11, 19, 21, 29])) {
                    $num += 1;
                    break;
                }
            }
        }
        dd('num', $num);
        return $num == 5 ? true : false;
    }

    // 校验金钩钓，胡牌时其他都被碰牌，杠牌
    private static function checkJgd(array $cards, array $peng,
                                     array $gang)
    {
        $num = count($peng) + count($gang);
        if ($num == 4) {
            return true;
        }
        return false;
    }

    // 校验将对，由二、五、八组成的碰碰胡
    private static function checkJd(array $cards)
    {
        $state = true;
        foreach ($cards as $v) {
            foreach ($v as $m) {
                if (!in_array($m, [2, 5, 8, 12, 15, 18, 22, 25, 28])) {
                    $state = false;
                    break;
                }
            }
        }
        return $state;
    }


    // 绑定牌类别
    private static function bindType(array $cards, array $gang)
    {
        $gen = 0; //根
        $types = [];
        foreach ($cards as $k => $v) {
//            dd('v', $v);
            $count = count((array)$v);
//            dd('count', $count);
            if ($count == 2) {
                $types[] = 'd'; //对牌
            }
            if ($count == 3) {
                if ($v[0] == $v[1]) {
                    $types[] = 'p'; //碰牌
                } else {
                    $types[] = 's'; //顺牌
                }
            }
            if ($count == 4) {
                $types[] = 'g'; //杠牌
//                dd('in_array', [$gang, $v]);
                if (!in_array($v[0], $gang)) {
                    $gen += 1;
                }
            }
        }
        sort($types);
        return ['px' => implode('', $types), 'gen' => $gen];
    }

    // 绑定牌花色：字，条，筒
    private static function bindColor(array $cards)
    {
        $colors = [];
        foreach ($cards as $k => $v) {
            $num = $v[0];
            if ($num >= 1 && $num <= 9) {
                $colors[] = 1; //万
            }
            if ($num >= 11 && $num <= 19) {
                $colors[] = 2; //筒
            }
            if ($num >= 21 && $num <= 29) {
                $colors[] = 3; //条
            }
        }
        return array_unique($colors);
    }

    // 校验定缺
    public static function checkColor(array $cards, int $colorNum)
    {
        $colorArr = [
            1 => [1, 2, 3, 4, 5, 6, 7, 8, 9],
            2 => [11, 12, 13, 14, 15, 16, 17, 18, 19],
            3 => [21, 22, 23, 24, 25, 26, 27, 28, 29],
        ];
        $res = array_intersect($cards, $colorArr[$colorNum]);
        if (!empty($res)) {
            return false;
        }
        return true;
    }

    // 校验牌数
    public static function checkNum(array $cards)
    {
        //牌数小于14或者大于18，则必定不能胡牌
        $num = count($cards);
        if (($num < 14) || ($num > 18)) {
            return [];
        }
        if (!empty($res)) {
            return false;
        }
        return true;
    }

}